#ifndef SERVERBASE_H_
#define SERVERBASE_H_

#include <e32base.h>

#include "scatu/ShutdownTimer.h"
#include "scatu/ServerDefs.h"

namespace scatu {

template <typename ServerType, typename SessionType> // Uses CRTP in NewL
class CServerBase : public CServer2
    {
public:

    static CServer2* NewLC()
        {
        ServerType* self = new (ELeave) ServerType;
        CleanupStack::PushL(self);
        static_cast<CServerBase*>(self)->ConstructL();
        return self;
        }

    void AddSession() const
        {
        ++iSessionCount;
        iShutdown.Cancel();
        }
    
    void DropSession() const
        {
        if (--iSessionCount==0)
            iShutdown.Start();
        }
    
protected:
    CServerBase() : CServer2(0,ESharableSessions) {}
    virtual void ConstructL()
        {
        StartL(KServerName());
        iShutdown.ConstructL();
        // ensure that the server still exits even if the 1st client fails to connect
        iShutdown.Start();
        }
    
    CSession2* NewSessionL(const TVersion& /*aVersion*/, const RMessage2& /*aMessage*/) const
            { return new(ELeave) SessionType(); }
private:
    // Get rid of ugly const_cast in session by making these mutable
    mutable TInt iSessionCount;
    mutable CShutdown iShutdown;
    };

template<typename ServerType>
class CSessionBase : public CSession2
    {
private: // Just implement this and you should be set
    virtual void PopulateRequestArrayL(RServerRequestArray & aArray) = 0;

public:
    CSessionBase() {}
    void CreateL()
        {
        Server().AddSession();
        PopulateRequestArrayL(iRequests);
        }
    
protected:
    virtual ~CSessionBase()
        {
        iRequests.Close();
        Server().DropSession();
        }
    
    inline ServerType const & Server()
        { return *static_cast<ServerType const *>(CSession2::Server()); }
    
private:
    
    void ServiceL(const RMessage2& aMessage)
        {
        if(!iRequests.ServeMessageL(aMessage))
            PanicClient(aMessage, EPanicIllegalFunction);
        }
    
private: 
    RServerRequestArray iRequests;
    };

} // namespace scatu

#endif /* SERVERBASE_H_ */
